home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 25
/
Aminet 25 (1998)(GTI - Schatztruhe)[!][Jun 1998].iso
/
Aminet
/
hard
/
drivr
/
cnetdevice.lha
/
cnetdevice
/
src
/
cnetdevice.asm
< prev
next >
Wrap
Assembly Source File
|
1998-04-23
|
54KB
|
1,837 lines
;---------------------------------------------------------------------------
; PCMCIA ethernet card driver for A1200
;---------------------------------------------------------------------------
;
; HISTORY:
;
; 10-4-97 v0.1 - Created by Bruce Abbott (bhabbott@inhb.co.nz)
; *** First Aminet Release ***
;
; 29-4-97 v0.2 - Implemented CMD_ONLINE/OFFLINE/FLUSH (for Miami).
;
; - Enabled interrupts during RemoteWrite (no more serial
; port overruns!).
;
; 6-5-97 v0.3 - Added a flag so that we won't try to ReleaseCard()
; unless there was a successful OwnCard()!
;
; 17-5-97 v0.4 - CMD_CONFIGINTERFACE now overrides the default hardware
; address (for Maimi).
;
; - Device now goes offline if the PCMCIA card is removed.
;
; - CMD_ONEVENT implemented.
;
; - Loosened hardware address verification to accept the
; Accton EN2216.
;
; - Unrolled loops to improve data transfer speed. Now
; about 20% faster on an unexpanded A600.
;
; - Hack to fix problem with missed interrupts. Now we
; clear the Gayle interrupt bits instead of letting
; card.resource do it for us.
;
; *** Second Aminet Release ***
;
; 29-7-97 v0.5 - Accepts 802.3 packets (untested).
;
; - Sets BROADCAST bit in io_flags when appropriate.
;
; - Now examines PCMCIA attribute memory to determine
; value to write into Card Configuration Register.
;
; - If attribute memory not found, tries to open the file
; "s:cnetdev.config" to get Card Configuration Register
; offset, Configuration ID, and ROM Station Address.
;
; *** Third Aminet Release ***
;
;22-12-97 v0.6 - I/O addressing now supports 64KByte range (was 1KB).
;
; - Tighter data transfer loops, slightly faster on '030.
;
; - Accepts all Card Configuration Register address sizes.
;
; - Removed cnet.config stuff (replaced with hardware mod).
;
; - Now cards are hot-swappable.
;
; - Un-supported commands now return S2ERR_NOT_SUPPORTED.
;
; *** 4th Aminet Release ***
;
;21-4-98 v0.7 - fixed harmless bug in init_nic - remote DMA timeout test
; could not fail!
;
; - Now remembers copytobuf/copyfrombuf tags for each opener.
; Allows simultaneous use of eg. AmiTCP and Envoy.
;
; - OnEvent types ONLINE and OFFLINE now return immediately
; if the device is already in the wanted state.
;
; *** 5th Aminet Release ***
;debug = 1
opt i-,d-
output devs:networks/cnet.device
include amiga.i ; commodore includes (WB1.3)
include pcmcia.i ; card.resource etc.
include sanaii.i ; the essential network stuff
include cnet.i ; hardware specific stuff
VERSION = 0
REVISION = 7
; 1uS delay before nic register access
; May not be required with slower CPUs.
delay MACRO
; tst.b $bfe001 ; at least 1uS, even on fast machines
ENDM
;===========================================================================
Section 0,CODE
start_exe:
moveq #-1,D0 ; it's a device, not an application!
rts
romtag:
dc.w RTC_MATCHWORD ; RT_MATCHWORD
dc.l romtag ; RT_MATCHTAG
dc.l Endcode ; RT_ENDSKIP
dc.b RTF_AUTOINIT ; RT_FLAGS
dc.b VERSION ; RT_VERSION
dc.b NT_DEVICE ; RT_TYPE
dc.b 0 ; RT_PRI
dc.l DeviceName ; RT_NAME
dc.l IDString ; RT_IDSTRING
dc.l Init ; RT_INIT
Init:
dc.l dd_extsize ; data space size
dc.l funcTable ; pointer to function initializers
dc.l dataTable ; pointer to data initializers
dc.l initRoutine ; routine to run at startup
funcTable:
dc.w -1
dc.w Open_Device-funcTable
dc.w Close_Device-funcTable
dc.w _DevExpunge-funcTable
dc.w _Null-funcTable
dc.w _DevBeginIO-funcTable
dc.w _DevAbortIO-funcTable
dc.w -1
dataTable:
INITBYTE LN_TYPE,NT_DEVICE
INITLONG LN_NAME,DeviceName
INITBYTE LIB_FLAGS,LIBF_SUMUSED!LIBF_CHANGED
INITWORD LIB_VERSION,VERSION
INITWORD LIB_REVISION,REVISION
INITLONG LIB_IDSTRING,idString
dc.w 0
include debugs.i
;=======================================================
; initRoutine
;=======================================================
;
; Called after device has been allocated.
; This routine is single threaded
;
; input: a0 = seglist
; d0 = device
;
initRoutine:
movem.l d1-d7/a0-a5,-(A7)
move.l d0,a5
move.l a0,dd_SegList(a5) ; seglist for expunge
move.l 4,execbase ; local copy of execbase
move.l a5,d0
movem.l (A7)+,d1-d7/a0-a5
rts
_Null:
moveq #0,d0
rts
;=================================================================
; Open Device
;=================================================================
;
; error = Open_Device(device, ioreq, unitnum, flags)
; d0 a6 a1 d0 d1
;
Open_Device:
bug <"cnet: OpenDevice(ioreq $%lx, unit %ld)",10>,a1,d0
movem.l D2-D4/A2-A4/A6,-(A7)
move.l A6,A3 ; a3 = device
move.l A1,A4 ; a4 = ioreq
move.l D0,D4 ; d4 = unit
move.l a3,a1
bsr init_device ; init device data structures
move.l a3,a0
move.l a4,a1
move.l d4,d0
bsr Open_Unit ; open unit
move.l d0,io_unit(a4)
beq.s .error
btst #DDB_NICUP,dd_flags(a3) ; nic already initialised ?
bne.s .ok
move.l a3,a1
bsr init_card ; init PCMCIA card
tst.l d0
bne.s .error
move.l a3,a1
bsr init_nic ; set up nic
tst.l d0
beq.s .ok
.error:
move.l dd_cardres(a3),d0 ; did card.resource open ?
beq.s .nocard
move.l d0,a6
bclr #DDB_OWNED,dd_flags(a3) ; did we own card ?
beq.s .nocard
lea dd_cardhandle(a3),a1
moveq #CARDF_REMOVEHANDLE,d0
jsr _LVOReleaseCard(a6) ; release card
.nocard:
moveq #IOERR_OPENFAIL,d0 ; error, opendevice failed!
move.b d0,io_error(a4)
move.l d0,io_device(a4)
bug <"cnet: opendevice failed!",10,10>
bra.s .done
.ok:
btst #DDB_OFFLINE,dd_flags(a3) ; previously put offline ?
bne.s .opened
bset #DDB_ONLINE,dd_flags(a3) ; ready to accept packets
.opened:
moveq #0,d0
move.b d0,io_error(a4) ; complete the ioreq
move.b #NT_REPLYMSG,ln_type(a4)
addq.w #1,lib_OpenCnt(a3) ; opened successfully
bug <"cnet: opendevice OK",10,10>
.done:
movem.l (A7)+,D2-D4/A2-A4/A6
rts
;===============================================================
; unit=Open Unit(device, ioreq, unitnum)
; d0 a0 a1 d0
;===============================================================
;
; Get the caller's buffer copy callback vectors
;
Open_Unit:
movem.l D2-D6/A2-A5,-(A7)
move.l A0,A4 ; A4 = device
move.l A1,A5 ; A5 = ioreq
tst.l D0 ; only unit 0 is supported
bne .error
move.l ios2_buffermanagement(A5),D0 ; tag list supplied?
beq .ok
moveq #0,D2 ; d2 = tags found
move.l D0,A0 ; a0 = tag list
.next_tag:
move.l (A0)+,D0 ; d0 = tag number
beq .got_tags ; end of tag list?
move.l (A0)+,D1 ; d1 = tag value
cmp.l #S2_COPYFROMBUFF,D0
beq.s .from ; tag_copyfrombuf ?
cmp.l #S2_COPYTOBUFF,D0
bne.s .next_tag ; tag_copytobuf ?
.to:
move.l D1,D5 ; d5 = copy2buf
bset #0,D2 ; got the tag
bra .next_tag
.from:
move.l D1,D6 ; d6 = copyfrombuf
bset #1,D2 ; got the tag
bra .next_tag
.got_tags:
and.b #3,d2
cmp.w #3,D2 ; got both tags ?
bne.s .error
moveq #bufman_sizeof,d0
moveq #0,d1
move.l execbase(pc),a6 ; allocate memory for bufman vectors
jsr _LVOAllocMem(a6)
move.l d0,ios2_buffermanagement(a5) ; return bufman node
beq.s .error
move.l d0,a1
move.l d5,bufman_copytobuf(a1)
move.l d6,bufman_copyfrombuf(a1)
bug <"cnet: addbufman $%lx $%lx $%lx",10>,a1,d5,d6
lea dd_bufmanlist(a4),a0
jsr _LVOAddHead(a6) ; add to buffer management list
bra.s .ok
.error:
moveq #0,d0 ; return error
bra.s .done
.ok:
moveq #1,d0 ; return OK
.done:
movem.l (A7)+,D2-D6/A2-A5
rts
;============================================================
; Expunge Device
;============================================================
;
; called when system wants us to close down
;
_DevExpunge:
tst.w lib_opencnt(a6)
bne.s .done
bset #LIBB_DELEXP,lib_flags(a6)
.done:
moveq #0,d0
rts
;============================================================
; Close Device
;============================================================
;
; Seglist = CloseDevice(ioreq,device)
; d0 a1 a6
;
Close_Device:
bug <"cnet: CloseDevice(io$%lx",10>,a1
movem.l a2/a3/a6,-(sp)
move.l a1,a3 ; a3 = ioreq
move.w lib_OpenCnt(a6),d0
beq.s .done ; already closed ?
subq.w #1,d0
move.w d0,lib_OpenCnt(a6)
move.l ios2_buffermanagement(a3),d0
beq.s .done ; got a buffermanagement pointer ?
move.l d0,a2
move.l a2,a1
bug <"cnet: remove bufman $%lx",10>,a1
move.l execbase(pc),a6
jsr _LVORemove(a6) ; remove bufman struct from list
move.l a2,a1
moveq #bufman_sizeof,d0
jsr _LVOFreeMem(a6) ; discard buffer management struct
.done:
movem.l (sp)+,a2/a3/a6
moveq #0,d0 ; no seglist, cannot be unloaded!
rts
;===============================================================
; Dev_BeginIO
;===============================================================
; the entry point for all device commands
;
_DevBeginIO:
move.b #NT_MESSAGE,ln_type(A1) ; make sure type is message
moveq #0,d0
move.w io_command(A1),D0 ; get command number
cmp.w #S2_END,D0
bhs.s .error ; valid command?
lsl.w #2,D0
move.l cmds(PC,D0.w),D0 ; get command vector
bne.s .ok
.error:
move.b #IOERR_NOCMD,io_error(A1)
bra TermIO ; return invalid command
.ok:
clr.b io_error(A1) ; no errors yet
move.l D0,A0
jmp (A0) ; jump to command
; command vectors
cmds:
dc.l 0 ; 0
dc.l 0 ; 1
dc.l devcmd_read ; 2 = cmd_read
dc.l devcmd_write ; 3 = cmd_write
dc.l 0 ; 4
dc.l 0 ; 5
dc.l 0 ; 6
dc.l 0 ; 7
dc.l devcmd_flush ; 8 = cmd_flush
dc.l devcmd_devicequery ; 9 = S2_DEVICEQUERY
dc.l devcmd_getstationaddress ; 10= S2_GETSTATIONADDRESS
dc.l devcmd_configinterface ; 11= S2_CONFIGINTERFACE
dc.l 0 ; 12
dc.l 0 ; 13
dc.l devcmd_nosupport ; 14= S2_ADDMULTICASTADDRESS
dc.l devcmd_nosupport ; 15= S2_DELMULTICASTADDRESS
dc.l devcmd_nosupport ; 16= S2_MULTICAST
dc.l devcmd_broadcast ; 17= S2_BROADCAST
dc.l devcmd_tracktype ; 18= S2_TRACKTYPE
dc.l devcmd_untracktype ; 19= S2_UNTRACKTYPE
dc.l devcmd_nosupport ; 20= S2_GETTYPESTATS
dc.l devcmd_nosupport ; 21= S2_GETSPECIALSTATS
dc.l devcmd_nosupport ; 22= S2_GETGLOBALSTATS
dc.l devcmd_onevent ; 23= S2_ONEVENT
dc.l devcmd_nosupport ; 24= S2_READORPHAN
dc.l devcmd_online ; 25= S2_ONLINE
dc.l devcmd_offline ; 26= S2_OFFLINE
;====================================================================
; Abort_IO
;====================================================================
;
; try to cancel a pending ioreq
;
_DevAbortIO:
movem.l A2/A6,-(A7)
move.l A1,A2
moveq #-1,D0 ; assume failure
cmp.b #NT_MESSAGE,ln_type(A2) ; only cancel queued ioreq's
bne.s .done
move.l execbase(PC),A6
jsr _LVODisable(A6)
move.l A2,A1
jsr _LVORemove(A6) ; remove ioreq from list
move.b #IOERR_ABORTED,io_error(A2)
move.l A2,A1
jsr _LVOReplyMsg(A6) ; reply to originator's message
jsr _LVOEnable(A6)
moveq #0,D0 ; aborted OK
.done:
movem.l (A7)+,A2/A6
rts
;===========================================================
; termio(ioreq)
; a1
;===========================================================
;
; return completed ioreq to sender.
;
TermIO:
movem.l A2/A6,-(A7)
move.l A1,A2
move.b io_error(a1),d0 ; completed OK ?
beq.s .noerr
move.l io_device(a2),A0
moveq #S2EVENT_ERROR,D0
bsr DoEvent ; do event for error
.noerr:
move.b #NT_REPLYMSG,ln_type(A2)
btst #IOB_QUICK,io_flags(A2)
bne.s .quick ; does sender need a reply ?
move.l A2,A1
move.l execbase(PC),A6
jsr _LVOReplyMsg(A6) ; send reply
.quick
.done:
movem.l (A7)+,A2/A6
rts
;====================================================
; CMD_READ
;====================================================
;
devcmd_read:
movem.l A2/A3/A6,-(A7)
move.l A1,A2 ; A2 = ioreq
move.l io_device(A2),A3
btst #DDB_CONFIGURED,dd_flags(A3) ; configured ?
bne.s .configured
move.b #S2ERR_BAD_STATE,io_error(A2)
moveq #S2WERR_NOT_CONFIGURED,D0
move.l D0,ios2_WireError(A2) ; error, device is not configured
bra.s .error
.configured:
bclr #IOB_QUICK,io_flags(A2) ; must be queued
move.l execbase(PC),A6
jsr _LVODisable(A6)
lea dd_readlist(A3),A0
move.l A2,A1
jsr _LVOAddTail(A6) ; add ioreq to read queue
jsr _LVOEnable(A6)
bra.s .done
.error:
move.l A2,A1
bsr TermIO ; terminate with error
.done:
movem.l (A7)+,A2/A3/A6
rts
;======================================================
; CMD_WRITE
;======================================================
;
devcmd_write:
movem.l A2/A3/A6,-(A7)
move.l A1,A2 ; A2 = ioreq
move.l io_device(A2),A3
btst #DDB_ONLINE,dd_flags(A3) ; online ?
bne.s .online
move.b #S2ERR_OUTOFSERVICE,io_error(A2)
moveq #S2WERR_UNIT_OFFLINE,D0
move.l D0,ios2_WireError(A2) ; error, device is offline
bra .error
.online:
btst #DDB_CONFIGURED,dd_flags(A3) ; configured ?
bne.s .configured
move.b #S2ERR_BAD_STATE,io_error(A2)
moveq #S2WERR_NOT_CONFIGURED,D0
move.l D0,ios2_WireError(A2) ; error, not configured
bra .error
.configured:
btst #SANA2IOB_RAW,io_flags(A2) ; raw packets ?
beq.s .cooked
move.l ios2_DataLength(A2),D1
cmp.l #RAWPKT_SIZE,D1
bls.s .goodlen ; check packet size
bra.s .toobig
.cooked:
move.l ios2_DataLength(A2),D1
cmp.l #ETHERPKT_SIZE,D1
bls.s .goodlen
.toobig:
move.b #S2ERR_MTU_EXCEEDED,io_error(A2) ; oops! packet too big
clr.l ios2_WireError(A2)
bra .error
.goodlen:
bclr #IOB_QUICK,io_flags(A2) ; must be queued
move.l execbase(PC),A6
jsr _LVODisable(A6)
lea dd_writelist(A3),A0
move.l A2,A1
jsr _LVOAddTail(A6) ; add ioreq to write queue
jsr _LVOEnable(A6)
lea dd_txint(A3),A1
jsr _LVOCause(A6) ; start tx
bra.s .done
.error:
move.l A2,A1
bsr TermIO ; terminate with error
.done:
movem.l (A7)+,A2/A3/A6
rts
;==============================================
; CMD_FLUSH
;==============================================
;
devcmd_flush:
movem.l A1/A2/A6,-(A7)
move.l io_device(A1),A2
move.l execbase(PC),A6
jsr _LVODisable(A6)
bra.s .flushreads
.readloop:
move.l D0,A1
move.b #IOERR_ABORTED,io_error(A1)
jsr _LVOReplyMsg(A6) ; abort all Read requests
.flushreads:
lea dd_readlist(A2),A0
jsr _LVORemHead(A6)
tst.l D0
bne.s .readloop
bra.s .flushwrites
.writeloop:
move.l D0,A1
move.b #IOERR_ABORTED,io_error(A1)
jsr _LVOReplyMsg(A6) ; abort all Write requests
.flushwrites:
lea dd_writelist(A2),A0
jsr _LVORemHead(A6)
tst.l D0
bne.s .writeloop
bra.s .flushevents
.eventloop:
move.l D0,A1 ; abort all Event requests
move.b #IOERR_ABORTED,io_error(A1)
jsr _LVOReplyMsg(A6)
.flushevents:
lea dd_eventlist(A2),A0
jsr _LVORemHead(A6)
tst.l D0
bne.s .eventloop
jsr _LVOEnable(A6)
movem.l (A7)+,A1/A2/A6
bra TermIO
;==============================================
; CMD_ONLINE
;==============================================
;
; Try to put device online
;
devcmd_online:
bug <"cnet: cmd_online",10>
move.l a1,-(a7)
move.l io_device(a1),a0
btst #DDB_CONFIGURED,dd_flags(a0) ; won't go online unless configured!
beq.s .error
btst #DDB_NICUP,dd_flags(a0) ; nic initialised ?
beq.s .error
bclr #DDB_OFFLINE,dd_flags(a0)
bset #DDB_ONLINE,dd_flags(a0) ; already online ?
bne.s .done
move.b dd_rcr(a0),nic_rcr ; set receiver to normal mode
moveq #S2EVENT_ONLINE,D0
bsr DoEvent ; return any ONLINE events
bra.s .done
.error:
move.b #S2ERR_OUTOFSERVICE,io_error(a1)
moveq #S2WERR_UNIT_OFFLINE,d0
move.l d0,ios2_wireerror(a1)
.done:
move.l (a7)+,a1
bra TermIO
;==============================================
; CMD_OFFLINE
;==============================================
;
; take device offline
;
devcmd_offline:
bug <"cnet: cmd_offline",10>
move.l a1,-(a7)
move.l io_device(a1),a0
bset #DDB_OFFLINE,dd_flags(a0)
bclr #DDB_ONLINE,dd_flags(a0) ; already offline ?
beq.s .done
btst #DDB_NICUP,dd_flags(a0)
beq.s .nicoff
move.b #DSRC_MON,nic_rcr ; set receiver to monitor mode
.nicoff:
moveq #S2EVENT_OFFLINE,D0
bsr DoEvent ; return any OFFLINE events
.done:
move.l (a7)+,a1
bra TermIO
;==============================================
; CMD_ONEVENT
;==============================================
;
; queue up event requests
;
; online/offline return immediately if the
; conditon is meet.
;
;
devcmd_onevent:
bug <"cnet: cmd_OnEvent $%08lx ">,ios2_wireerror(a1)
movem.l a1/a6,-(a7)
move.l ios2_wireerror(a1),d0
and.l #S2EVENT_ONLINE,d0 ; waiting for online event ?
beq.s .noton
btst #DDB_ONLINE,dd_flags(a1) ; currently online ?
bne.s .rtn
bra.s .queue
.noton:
move.l ios2_wireerror(a1),d0
and.l #S2EVENT_OFFLINE,d0 ; waiting for offline event ?
beq.s .queue
btst #DDB_ONLINE,dd_flags(a1) ; currently offline ?
bne.s .queue
.rtn:
bug <"is (on|off)line",10>
move.l d0,ios2_wireerror(a1) ; return immediately
clr.b io_error(a1)
bra.s .done
.queue:
bug <"queued",10>
move.l io_device(a1),a0
bclr #IOB_QUICK,io_flags(a1) ; must be queued
move.l execbase(PC),A6
jsr _LVODisable(A6)
lea dd_eventlist(A0),A0
jsr _LVOAddTail(A6) ; add ioreq to event queue
jsr _LVOEnable(A6)
.done:
movem.l (a7)+,a1/a6
bra TermIO
;==============================================
; CMD_DEVICEQUERY
;==============================================
;
devcmd_devicequery:
bug <"cnet: cmd_devicequery",10>
move.l A1,-(A7)
move.l ios2_statdata(A1),A0 ; a0 = caller's buffer
move.l (A0),D1 ; D1 = buffer size
move.l size_supplied(pc),D0
cmp.l D0,D1 ; enough space to store info?
bhs.s .get
clr.l S2DQ_SIZESUPPLIED(A0) ; nope!
bra.s .done
.get:
lea S2DQ_SIZESUPPLIED(A0),A1
lea size_supplied(pc),A0
subq.l #4,D0 ; skip bytes_available
bra.s .copy
.copyloop:
move.b (A0)+,(A1)+ ; copy info to caller's buffer
.copy:
dbf D0,.copyloop
.done:
move.l (A7)+,A1
bra TermIO
;==============================================
; CMD_GETSTATIONADDRESS
;==============================================
;
devcmd_getstationaddress:
bug <"cnet: cmd_getstationaddress",10>
move.l A1,-(A7)
move.l io_device(A1),A0
lea dd_stationaddress(A0),A0
move.l A0,D1
lea ios2_srcaddr(A1),A1
move.w #ETHER_ADDR_SIZE-1,D0
.copysrc:
move.b (A0)+,(A1)+ ; source address = station address
dbf d0,.copysrc
move.l (A7),A1
lea ios2_dstaddr(A1),A1
move.w #ETHER_ADDR_SIZE-1,D0
move.l D1,A0
.copydst:
moveq #0,d1
move.b (A0)+,d1
move.b d1,(A1)+ ; dest address = station address
dbf d0,.copydst
move.l (A7)+,A1
bra TermIO
;==============================================
; CMD_CONFIGINTERFACE
;==============================================
;
; NOTE: a default station address has already
; been set by init_nic
;
devcmd_configinterface:
bug <"cnet: cmd_ConfigInterface",10>
move.l a6,-(sp)
move.l io_device(a1),a0
move.l ios2_srcaddr(a1),d0
ble .done ; check for valid address
move.l d0,dd_stationaddress(a0)
move.w ios2_srcaddr+4(a1),dd_stationaddress+4(a0)
move.l execbase(pc),a6
jsr _LVODisable(a6)
move.b nic_cr,d1 ; remember current command
delay
move.b #DSCM_NODMA|DSCM_PG1,nic_cr ; select bank 1
delay
move.b dd_stationaddress+0(a0),nic_par0
delay
move.b dd_stationaddress+1(a0),nic_par1
delay
move.b dd_stationaddress+2(a0),nic_par2
delay ; set station address
move.b dd_stationaddress+3(a0),nic_par3
delay
move.b dd_stationaddress+4(a0),nic_par4
delay
move.b dd_stationaddress+5(a0),nic_par5
delay
move.b d1,nic_cr ; restore command
jsr _LVOEnable(a6)
bset #DDB_CONFIGURED,dd_flags(a0) ; now configured
.done:
move.l (sp)+,a6
bra TermIO
;==============================================
; CMD_BROADCAST
;==============================================
;
devcmd_broadcast:
bug <"cnet: cmd_broadcast",10>
move.w #ETHER_ADDR_SIZE-1,D0
moveq #0,d1
.loop:
move.b #255,ios2_dstaddr(a1,d1.w) ; dest address = BROADCAST
addq.w #1,d1
dbf d0,.loop
.doit:
bra devcmd_write
;=========================================================
; CMD_TRACKTYPE
;=========================================================
;
; This function adds a packet type to the
; list of those that are being tracked.
;
devcmd_tracktype:
bug <"cnet: cmd_tracktype %ld",10>,ios2_packettype(a1)
bra TermIO ; but we won't actually track anything
;=========================================================
; CMD_UNTRACKTYPE
;=========================================================
;
; This function removes a packet type from
; the list of those that are being tracked.
;
devcmd_untracktype:
bug <"cnet: cmd_untracktype %ld",10>,ios2_packettype(a1)
bra TermIO ; but we won't actually untrack anything
;=========================================================
; commands not supported
;=========================================================
;
devcmd_nosupport:
bug <"cnet: Unsupported command %d",10>,io_command-2(a1)
move.b #S2ERR_NOT_SUPPORTED,io_error(a1)
moveq #S2WERR_GENERIC_ERROR,d0
move.l d0,ios2_wireerror(a1)
bra TermIO
;==========================================================
; doevent(device, events)
; a0 d0
;==========================================================
;
; called when an 'important' event occurs
;
DoEvent:
bug <"cnet: doevent $%08lx ...">,d0
movem.l D2/A2/A6,-(A7)
move.l D0,D2
move.l dd_eventlist(A0),A2 ; get first ioreq
move.l execbase(PC),A6
jsr _LVODisable(A6) ; lock eventlist
bra.s .start
.loop:
move.l ios2_wireerror(A2),D0
and.l D2,D0 ; ioreq for our events?
beq.s .next
move.l D0,ios2_wireerror(A2) ; set the actual events
move.l A2,A1
jsr _LVORemove(A6) ; remove ioreq from list
move.b #NT_REPLYMSG,ln_type(A2)
move.l A2,A1
bug <"cnet: returned eventreq $%lx",10>,a1
move.l execbase(PC),A6
jsr _LVOReplyMsg(A6) ; send reply to ioreq owner
.next:
move.l (A2),A2 ; next ioreq
.start:
tst.l (A2) ; last ioreq ?
bne.s .loop
.done:
bug <10,"cnet: doevent done",10>
jsr _LVOEnable(A6) ; unlock eventlist
movem.l (A7)+,D2/A2/A6
rts
;======================
; delay approx 1.5mS
;======================
;
delay1500:
move.l D0,-(A7)
move.w #1500,D0
.loop:
tst.b $bfe001 ; wait 1uS
dbf D0,.loop
move.l (A7)+,D0
rts
;==================================================================
; RemoteRead(buffer, nicbuffer, length)
; a1 d0.w d1.w
;==================================================================
;
; Get a copy of data stored in the network card's onboard RAM.
;
; buffer = Amiga RAM
;
; nicbuffer = 16 bit address in card memory
;
RemoteRead:
addq.w #1,d1 ; bump up count to even value
bclr #0,d1
delay
swap d1
move.b nic_cr,d1 ; save old command
swap d1
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b d1,nic_rbcr0 ; set count.lo
ror.w #8,D1
delay
move.b d1,nic_rbcr1 ; set count.hi
delay
move.b d0,nic_rsar0 ; set address.lo
ror.w #8,D0
delay
move.b D0,nic_rsar1 ; set address.hi
delay
move.b #DSCM_RREAD|DSCM_START,nic_cr ; request Remote Read
ror.w #8,d1
move.w d1,d0
and.w #%0000000000011110,d0
neg.w d0
lsr.w #5,d1
lea nic_data,a0
jmp .startread(pc,d0.w)
.dmaread:
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
move.w (A0),(A1)+
.startread:
dbf d1,.dmaread
move.b #DSIS_RDC,nic_isr ; Remote DMA Complete
swap d1
delay
move.b d1,nic_cr ; restore old command
rts
;=================================================================
; RemoteWrite( buffer, nicbuffer, count )
; a1 d0.w d1.w
;=================================================================
;
; Puts data into the network card's onboard RAM
;
; buffer = Amiga memory
;
; nicbuffer = 16 bit address in card RAM
;
;
RemoteWrite:
addq.w #1,D1
bclr #0,D1 ; bump up count to even value
swap d1
delay
move.b nic_cr,d1 ; save old command
swap d1
delay
move.b #DSIS_RDC,nic_isr ; remote DMA complete
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
delay
move.b D0,nic_rsar0 ; set address.lo
lsr.w #8,D0
delay
move.b D0,nic_rsar1 ; set address.hi
delay
move.b D1,nic_rbcr0 ; set count.lo
ror.w #8,D1
delay
move.b D1,nic_rbcr1 ; set count.hi
delay
move.b #DSCM_START|DSCM_RWRITE,nic_cr ; request remote write
ror.w #8,D1
move.w d1,d0
and.w #%0000000000011110,d0
neg.w d0
lsr.w #5,d1
lea nic_data,a0
jmp .startwrite(pc,d0.w)
.dmawrite:
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
move.w (A1)+,(A0)
.startwrite:
dbf d1,.dmawrite
move.w #30000,D0 ; set timeout
.check:
delay
move.b nic_isr,d1 ; wait for remote DMA complete
and.b #DSIS_RDC,d1
bne.s .OK
dbf D0,.check
moveq #1,D0 ; timed out error
bra.s .done
.ok:
moveq #0,D0 ; OK
.done:
delay
move.b #DSIS_RDC,nic_isr ; Remote DMA complete
swap d1
delay
move.b d1,nic_cr ; restore old command
rts
;=========================================================
; reset_nic()
;=========================================================
;
reset_nic:
delay
move.b nic_rst,D0 ; start reset pulse
delay
move.b D0,nic_rst ; end reset pulse
delay
move.b #DSCM_NODMA|DSCM_STOP,nic_cr ; stop controller
bsr delay1500 ; wait 1.5mS
move.b #$ff,nic_isr ; clear all nic ints
rts
;========================================================================
; init_nic(device)
; a1
;========================================================================
;
; set up the network card for online operation
;
; Here we also get the hardware station address from the nic's ROM. The
; CNet card sometimes doesn't read its ROM correctly, so in this case we
; use a fixed address instead.
;
init_nic:
bug <"cnet: init_nic ">
movem.l D2/A5/A6,-(A7)
move.l A1,A5 ; a5 = device data
move.l execbase(PC),A6
jsr _LVODisable(A6) ; ignore ints while setting up
btst #DDB_NICUP,dd_flags(a5)
bne .ok ; already initialised ?
move.b #DSDC_WTS|DSDC_FT1|DSDC_BMS,dd_dcr(A5) ; Word Xfer, FIFO, Burst
move.b #DSRC_AB,dd_rcr(A5) ; accept broadcast packets
move.b #INTMASK,dd_imr(A5) ; accept useful interrupts
bsr reset_nic ; reset the controller
delay
move.b nic_cr,D0 ; get command
cmp.b #DSCM_NODMA|DSCM_STOP,d0
bne .error ; is it correct ?
delay
move.b dd_dcr(A5),nic_dcr ; set data configuration register
delay
move.b #0,nic_rbcr0 ; clear remote byte count
delay
move.b #0,nic_rbcr1 ; ''
delay
move.b #DSRC_MON,nic_rcr ; set rx to monitor mode
delay
move.b #DSTC_LB0,nic_tcr ; set tx to loopback mode 1
delay
move.b #(RBUFEND/256)-1,nic_bnry ; set boundary page
delay
move.b #RBUF/256,nic_pstart ; set start of rx ring buffer
delay
move.b #RBUFEND/256,nic_pstop ; set end of rx ring buffer
delay
move.b #$ff,nic_isr ; clear all interrupts
delay
move.b #0,nic_imr ; no interrupts allowed
delay
move.b nic_rsr,d0
delay
move.b nic_ncr,d0
delay
move.b nic_cntr0,d0 ; read status registers
delay
move.b nic_cntr1,d0
delay
move.b nic_cntr2,d0
delay
move.b #ETHER_ADDR_SIZE*2,nic_rbcr0 ; byte count low = (words)
delay
move.b #0,nic_rbcr1 ; byte count high = 0
delay
move.b #0,nic_rsar0 ; remote start addr low = 0 (ROM)
delay
move.b #0,nic_rsar1 ; remote start addr high = 0 (ROM)
delay
move.b #DSCM_RREAD,nic_cr ; start remote read to get
delay ; station address from ROM
lea dd_romstationaddress(a5),A0
move.w #ETHER_ADDR_SIZE-1,D0
.getaddr:
move.b nic_data,(A0)+ ; get ROM station address
dbf D0,.getaddr ; NOTE: 'move.b' as ROM is 8 bit
move.w #30000,d1
.waitloop:
delay
move.b nic_isr,d0
and.b #DSIS_RDC,d0 ; wait for remote DMA complete
dbne d1,.waitloop
tst.b d0
beq .error ; error if timed out
delay
move.b #DSIS_RDC,nic_isr ; clear remote DMA complete int
lea dd_romstationaddress(a5),a0
btst #7,(a0)
bne.s .badaddr ; good station address ?
move.l 2(a0),d0
beq.s .badaddr
cmp.l #-1,d0
bne.s .gotstation
.badaddr:
lea default_address(pc),a0 ; use known good station address
.gotstation:
lea dd_stationaddress(a5),a1
moveq #ETHER_ADDR_SIZE-1,d0
.copyaddr:
move.b (a0)+,(a1)+ ; copy address to device data
dbf d0,.copyaddr
delay
move.b #DSCM_NODMA|DSCM_PG1|DSCM_STOP,nic_cr ; select bank 1
delay
move.b dd_stationaddress+0(a5),nic_par0
delay
move.b dd_stationaddress+1(a5),nic_par1
delay
move.b dd_stationaddress+2(a5),nic_par2
delay ; set station address
move.b dd_stationaddress+3(a5),nic_par3
delay
move.b dd_stationaddress+4(a5),nic_par4
delay
move.b dd_stationaddress+5(a5),nic_par5
delay
move.b #RBUF/256,nic_curr ; set current page for rx
move.b #DSCM_NODMA|DSCM_START,d0
delay
move.b d0,nic_cr ; start controller
delay
cmp.b nic_cr,D0
bne .error ; command accepted ?
delay
move.b dd_rcr(A5),nic_rcr ; normal rx mode
delay
move.b #0,nic_tcr ; loopback mode off
delay
move.b #TBUF/256,nic_tpsr ; init tx start page
delay
move.b #$ff,nic_isr ; clear all interrupts
delay
move.b dd_imr(A5),nic_imr ; enable nic interrupts
.ok:
bset #DDB_NICUP,dd_flags(a5) ; nic is initialised
bug <"OK",10>
moveq #0,D0
bra.s .done ; return OK
.error:
bsr reset_nic ; reset nic after malfunction
.bad:
bug <"failed",10>
moveq #-1,D0 ; return error
.done:
jsr _LVOEnable(A6) ; allow interrupt processing
movem.l (A7)+,D2/A5/A6
rts
;========================================================
; txintcode(device)
; a1
;========================================================
;
; send packets to network card. packets will be put
; into the card's onboard 16 bit ram, and then
; transmitted to the wire.
;
txintcode:
movem.l D4-D7/A2-A4/A6,-(A7)
move.l A1,A4 ; a4 = device
.next:
btst #DDB_TX,dd_flags(a4) ; quit if tx in progress (status int
bne .done ; will restart us when tx complete)
.getreq:
lea dd_writelist(A4),A0
move.l execbase(pc),a6 ; remove top ioreq
jsr _LVORemHead(A6)
tst.l D0 ; any ioreqs to process?
beq .done
move.l D0,A3 ; A3 = ioreq
lea txbuffer,A1 ; A1 = our internal packet buffer
btst #SANA2IOB_RAW,io_flags(A3) ; raw packets?
beq.s .notraw
move.l ios2_datalength(A3),D6 ; raw packet is full length
bra.s .send
.notraw:
lea ios2_dstaddr(A3),A0
moveq #ETHER_ADDR_SIZE-1,D0
.copy1:
move.b (A0)+,(A1)+ ; insert dest stationaddr into packet
dbra D0,.copy1
lea dd_stationaddress(A4),A0
moveq #ETHER_ADDR_SIZE-1,D0
.copy2:
move.b (A0)+,(A1)+ ; insert src address into packet
dbra D0,.copy2
move.l ios2_packettype(A3),D0 ; insert packettype into packet
move.w D0,(A1)+
moveq #ether_data,D6
add.l ios2_datalength(A3),D6 ; d6 = length of header + data
.send:
move.l a1,a0
move.l ios2_data(A3),A1
move.l ios2_datalength(A3),D0
move.l ios2_buffermanagement(a3),a2
move.l bufman_copyfrombuf(a2),a2
jsr (a2) ; call copyfrombuf
moveq #ETHER_MIN_LEN,D0
cmp.l D0,D6
bge.s .min ; d6 adjusted to legal packet size
move.l D0,D6
.min:
; bug <"cnet: writepacket %ld bytes",10>,d6
move.l D6,D1
move.w #TBUF,d0
lea txbuffer,A1
bsr RemoteWrite ; put packet into nic tx buffer
tst.l D0
bne.s .termio
move.l execbase(PC),A6 ; disable interrupts during tx setup
jsr _LVODisable(A6)
bset #DDB_TX,dd_flags(A4) ; set our "buffer full" flag
delay
move.b D6,nic_tbcr0 ; set tx byte count lo
ror.w #8,D6
delay
move.b D6,nic_tbcr1 ; set tx byte count hi
delay
move.b #DSCM_NODMA|DSCM_TRANS|DSCM_START,nic_cr ; start tx
move.l execbase(PC),A6
jsr _LVOEnable(A6) ; enable interrupts
.termio:
move.l A3,A1
bsr TermIO ; finish IOrequest
bra .next ; process next ioreq
.done:
movem.l (A7)+,D4-D7/A2-A4/A6
moveq #0,d0
rts
;============================================================
; rxintcode(device)
; a1
;============================================================
;
; service rx interrupts
;
rxintcode:
movem.l D6/D7/A3-A6,-(A7)
move.l A1,A3 ; a3 = device
move.l execbase(PC),A6
.nextpage:
jsr _LVODisable(A6)
delay
move.b #DSCM_NODMA|DSCM_PG1|DSCM_START,nic_cr ; select bank 1
moveq #0,D7
move.b nic_curr,D7 ; d7 = current page
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
jsr _LVOEnable(A6)
moveq #0,D6
delay
move.b nic_bnry,D6
addq.w #1,D6 ; d6 = next page (boundary+1)
cmp.w #RBUFEND/256,D6
blo.s .nowrap ; end of buffer mem ?
moveq #RBUF/256,D6 ; wrap around to start
.nowrap:
cmp.w D6,D7 ; current page = next page ?
beq .done ; if so then nothing to get
move.w D6,D0
asl.w #8,D0 ; d0 = 16 bit page address
lea rx_header(pc),A1 ; a1 = buffer
moveq #20,D1 ; 20 bytes to get
bsr RemoteRead ; get packet header
move.b rx_header+prhdr_status(pc),d0
and.b #DSRS_RPC,d0 ; complete packet received ?
bne.s .goodpacket
addq.l #1,dd_errors(a3) ; another packet error
bra.s .next
.goodpacket:
move.l A3,A0
move.w D6,D0
lea rx_header(pc),A1
bsr readpacket ; read whole packet into ioreqs
.next:
moveq #0,D0
move.b rx_header+prhdr_nxtpg(pc),D0 ; get next page number
move.w D0,D7
subq.w #1,D0 ; nxtpage-1 = new boundary
cmp.w #RBUF/256,D0
bge.s .boundary ; wrap if before 1st page
moveq #(RBUFEND/256)-1,D0
.boundary:
delay
move.b D0,nic_bnry ; set new boundary
bra .nextpage ; back for more
.done:
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; select bank 0
jsr _LVODisable(A6)
delay
move.b nic_rsr,d0 ; read rx status
delay
move.b nic_cntr0,D0
delay
move.b nic_cntr1,D0 ; read counters
delay
move.b nic_cntr2,D0
or.b #DSIM_OVWE|DSIM_RXEE|DSIM_PRXE,dd_imr(A3)
move.b dd_imr(a3),nic_imr ; allow rx interrupts
jsr _LVOEnable(A6)
movem.l (A7)+,D6/D7/A3-A6
moveq #0,D0
rts
;==============================================================
; readpacket( device, pkthdr, page )
; a0 a1 d0.w
;==============================================================
;
; get packet from network card and feed it to next ioreq
;
; Inputs:
;
; pkthdr = packet header info extracted from nic
;
; page = 256 byte page in nic RAM that holds packet
;
;
readpacket:
movem.l D3-D7/A2-A6,-(A7)
move.l D0,D7 ; D7 = page
move.l A0,A5 ; A5 = device
move.l A1,A4 ; a4 = header
moveq #0,D6
move.b prhdr_sz1(A4),D6
lsl.w #8,D6 ; D6 = packet data length
move.b prhdr_sz0(A4),D6
sub.w #prhdr_sizeof+ether_data,D6 ; D6 = length of user data
moveq #0,D3
move.w prhdr_sizeof+ether_type(A4),D3 ; d3 = type
; bug <"cnet: readpacket type %ld, %ld bytes",10>,d3,d6
move.l dd_readlist(A5),A3 ; a3 = first ioreq
bra.s .getreq ; find a suitable ioreq
.checkreq:
cmp.l ios2_packettype(A3),D3 ; does it want our packet ?
beq.s .gotreq
cmp.w #1500,d3
bhi.s .nextreq ; accept 802.3 packets
cmp.l #1500,ios2_packettype(A3)
bls.s .gotreq
.nextreq:
move.l D1,A3 ; a3 = next ioreq in list
.getreq:
move.l (A3),D1 ; end of list ?
bne.s .checkreq
bra .done
.gotreq:
move.l A3,A1
move.l execbase(PC),A6
jsr _LVORemove(A6) ; remove ioreq from list
lea ios2_dstaddr(A3),A0
moveq #ETHER_ADDR_SIZE-1,D0
.dst:
move.b (A4)+,(A0)+ ; extract the dest address
dbf D0,.dst
cmp.w #$ffff,ios2_dstaddr(a3)
bne.s .getsrc ; address = Broadcast ?
cmp.l #$ffffffff,ios2_dstaddr+2(a3)
bne.s .getsrc
bset #SANA2IOB_BCAST,io_flags(a3) ; set BROADCAST flag in ioreq
.getsrc:
lea ios2_srcaddr(A3),A0
moveq #ETHER_ADDR_SIZE-1,D0
.src:
move.b (A4)+,(A0)+ ; extract the src address
dbf D0,.src
move.w D7,D5
asl.w #8,D5 ; address=page*256
add.w #prhdr_sizeof+ether_data,D5 ; skip pageheader and etherheader
btst #SANA2IOB_RAW,io_flags(A3)
beq.s .getpacket ; is etherheader wanted ?
moveq #ether_data,D0
add.l D0,D6 ; add header length for raw packet
sub.w D0,D5 ; backup nic address to include header
.getpacket:
lea rxbuffer,A1
move.w D5,D0
move.w D6,D1
bsr RemoteRead ; get packet from network card's RAM
move.l ios2_data(A3),A0
lea rxbuffer,A1
move.l D6,ios2_datalength(A3) ; set data length in ioreq
move.l d6,d0
move.l ios2_buffermanagement(a3),a2
move.l bufman_copytobuf(a2),a2
jsr (a2) ; call copytobuf
move.l A3,A1
bsr TermIO ; IO finished
.done:
movem.l (A7)+,D3-D7/A2-A6
rts
;======================================================================
; init_card(device)
; a1
;======================================================================
;
; Initialise PCMCIA card
;
init_card:
bug <"cnet: init_card ">
movem.l D3-D6/A3/A6,-(A7)
move.l a1,a3 ; a3 = device
btst #DDB_OWNED,dd_flags(a3) ; do we own the card already?
bne .owned
move.l dd_cardres(a3),d0
bne.s .gotres
lea cardname(pc),a1
move.l execbase(pc),a6
jsr _LVOOpenResource(a6) ; open credit card resource
move.l d0,dd_cardres(a3)
beq .error
.gotres:
lea dd_cardhandle(a3),a1
lea dd_cardremoved(a3),a0 ; init interrupt for card removed
move.l a3,is_data(a0)
move.l #card_removed_code,is_code(a0)
move.l a0,cah_CardRemoved(a1)
lea dd_cardinserted(a3),a0 ; init interrupt for card inserted
move.l a3,is_data(a0)
move.l #card_inserted_code,is_code(a0)
move.l a0,cah_CardInserted(a1)
lea dd_cardstatus(a3),a0 ; init interrupt for status change
move.l a3,is_data(a0)
move.l #status_int_code,is_code(a0)
move.l a0,cah_CardStatus(a1)
lea devicename(pc),a0
move.l a0,ln_name(a1)
move.b #20,ln_pri(a1) ; high priority for I/O card
move.b #CARDF_IFAVAILABLE,cah_cardflags(a1)
move.l dd_cardres(a3),a6
jsr _LVOOwnCard(a6) ; own card (sets up interrupt vectors)
tst.l d0
bne .error
bset #DDB_CARDIN,dd_flags(a3) ; card is inserted
bset #DDB_OWNED,dd_flags(a3) ; card is now owned by us
.owned:
lea dd_cardhandle(a3),a1
lea tuple(pc),a0
moveq #CISTPL_FUNC_ID,d1
moveq #40,d0
move.l dd_cardres(a3),a6
jsr _LVOCopyTuple(a6) ; read function tuple
tst.l d0
beq .error
lea tuple(pc),a0
move.b 2(a0),d0
cmp.b #CISTPL_FUNCID_NETWORK,d0 ; must be a network card!
bne .error
lea dd_cardhandle(a3),a1
lea tuple(pc),a0
moveq #CISTPL_CONF_MAP,d1
moveq #40,d0
move.l dd_cardres(a3),a6
jsr _LVOCopyTuple(a6) ; read config map tuple
tst.l d0
beq .error
lea tuple(pc),a0
move.b 2(a0),d0
and.w #$03,d0 ; (number of address bytes)-1
moveq #0,d5
.getaddr:
lsl.l #8,d5
move.b 4(a0,d0.w),d5 ; extract config register address
dbf d0,.getaddr
and.l #$0001FFFF,d5 ; limit to attribute memory range
lea dd_cardhandle(a3),a1
moveq #CISTPL_CONFIG,d1
moveq #40,d0
jsr _LVOCopyTuple(a6) ; read 1st config tuple
tst.l d0
beq.s .error
lea dd_cardhandle(a3),a1
move.l #CARDF_DISABLE_WP|CARDF_ENABLE_DIGAUDIO,d1
jsr _LVOCardMiscControl(a6) ; enable card I/O functions
lea tuple(pc),a0
move.b 2(a0),d0 ; extract configuration ID value
.setconfig:
and.b #$3f,d0
lea AttrMem,a0
add.l d5,a0
move.b d0,(a0) ; put ID into card config register
bra.s .ok
.error:
bug <"failed",10>
moveq #-1,d0 ; card not available, return error
bra.s .done
.ok:
bug <"OK",10>
moveq #0,D0 ; card is active, return OK
.done:
movem.l (A7)+,D3-D6/A3/A6
rts
;=================================================================
; initialise device data structures
;=================================================================
;
; init_device(device)
; a1
;
init_device:
move.l A3,-(A7)
move.l A1,A3
bset #DDB_DEVINIT,dd_flags(A3) ; already initialised ?
bne .done
lea dd_readlist(A3),A0
move.l A0,mlh_tailpred(A0)
lea mlh_tail(A0),A1 ; New MinList for read queue
clr.l (A1)
move.l A1,(A0)
lea dd_writelist(A3),A0
move.l A0,mlh_tailpred(A0) ; New MinList for write queue
lea mlh_tail(A0),A1
clr.l (A1)
move.l A1,(A0)
lea dd_eventlist(A3),A0 ; New MinList for event queue
move.l A0,mlh_tailpred(A0)
lea mlh_tail(A0),A1
clr.l (A1)
move.l A1,(A0)
lea dd_bufmanlist(A3),A0 ; New MinList for bufman vectors
move.l A0,mlh_tailpred(A0)
lea mlh_tail(A0),A1
clr.l (A1)
move.l A1,(A0)
move.b #NT_INTERRUPT,dd_rxint+ln_type(a3)
move.b #16,dd_rxint+ln_pri(a3)
lea rxintname(pc),a0
move.l a0,dd_rxint+ln_name(a3) ; set up rx swi
lea rxintcode(pc),a0
move.l a0,dd_rxint+is_code(a3)
move.l a3,dd_rxint+is_data(a3)
move.b #NT_INTERRUPT,dd_txint+ln_type(a3)
move.b #0,dd_txint+ln_pri(a3)
lea txintname(pc),a0
move.l a0,dd_txint+ln_name(a3) ; set up tx swi
lea txintcode(pc),a0
move.l a0,dd_txint+is_code(a3)
move.l a3,dd_txint+is_data(a3)
.done:
move.l (A7)+,A3
rts
;============================================================
; PCMCIA status change interrupt
;============================================================
;
; Occurs whenever a PCMCIA status line changes
;
; eg. when the network card activates it's interrupt line
;
;
; entry: d0 = status change(s)
; a1 = device
;
; exit: d0 must be preserved!
;
status_int_code:
movem.l D2-D6/A2-A4,-(A7)
move.l D0,D6 ; d6 = status changes
move.l A1,A4 ; a4 = device
btst #DDB_NICUP,dd_flags(a4) ; is nic working ?
beq .done
move.b nic_cr,d5 ; save old command
delay
move.b #0,nic_imr ; prevent nic interrupts
bra .checkint
; interrupt service loop (D3 = interrupt status)
.intloop:
btst #DSIB_ROVRN,d3
beq .no_overflow
; receiver ring buffer overflowed (eek!)
addq.l #1,dd_overflows(a4)
delay
move.b #0,nic_rbcr0
delay
move.b #0,nic_rbcr1 ; reset remote byte count
delay
move.b #DSTC_LB0,nic_tcr
delay ; monitor mode
move.b #DSRC_MON,nic_rcr
delay
move.b #DSCM_NODMA|DSCM_START,nic_cr ; try to restart controller
delay
move.b #DSRC_AB,nic_rcr
delay ; normal rx mode
move.b #0,nic_tcr
.no_overflow:
btst #DSIB_RXE,d3
beq.s .norxerr
addq.l #1,dd_errors(a4)
delay
move.b nic_rsr,d0 ; read rx status
delay
move.b nic_cntr0,D0
delay
move.b nic_cntr1,D0 ; read counters
delay
move.b nic_cntr2,D0
bra.s .rx
.norxerr:
btst #DSIB_RX,d3
beq.s .no_rx
; new packet(s) arrived in receive ring buffer
.rx:
and.b #~(DSIM_OVWE|DSIM_RXEE|DSIM_PRXE),dd_imr(A4) ; ignore rx ints
lea dd_rxint(A4),A1
move.l execbase(PC),A6
jsr _LVOCause(A6) ; to copy packet(s) into waiting ioreqs
.no_rx:
btst #DSIB_TXE,d3
bne.s .tx
btst #DSIB_TX,d3
beq .no_tx
; a packet has just been transmitted
.tx:
moveq #0,d0
delay
move.b nic_ncr,d0 ; read collision count
add.l d0,dd_collisions(a4)
bclr #DDB_TX,dd_flags(A4) ; buffer now free
lea dd_txint(A4),A1
move.l execbase(PC),A6
jsr _LVOCause(A6) ; to transmit next packet
.no_tx:
btst #DSIB_CTRS,d3 ; counter overflow ?
bne.s .counter
bra.s .checkint ; all ints processed
; counter overflow
.counter:
delay
move.b nic_cntr0,D0
delay
move.b nic_cntr1,D0 ; read counters
delay
move.b nic_cntr2,D0
.checkint:
delay
move.b nic_isr,D3 ; D3 = nic interrupt status
delay
move.b d3,nic_isr ; clear current interrupt bit(s)
and.b dd_imr(a4),d3
bne .intloop ; any valid interrupts ?
.end:
delay
move.b d5,nic_cr ; restore old command
eor.b #$2c,d6
or.b #$c0,d6
move.b d6,$da9000 ; clear PCMCIA status change bits
delay
move.b dd_imr(a4),nic_imr ; enable nic interrupts
moveq #0,d0 ; don't clear status bits coz we did
.done:
movem.l (A7)+,D2-D6/A2-A4
rts
;============================================================
; PCMCIA Card Inserted interrupt
;============================================================
;
; Occurs whenever a PCMCIA card is plugged in
;
; NOTE: card.resource has given us ownership of the card
;
; entry: a1 = device
;
; exit: d0,d1,a0,a1,a5,a6 = scratch
;
card_inserted_code:
bug <"cnet: card inserted",10>
move.l a1,a5
bset #DDB_CARDIN,dd_flags(a5) ; card is inserted
bset #DDB_OWNED,dd_flags(a5) ; we own the card again
bsr init_card
tst.l d0 ; attempt to init pcmcia card
bne.s .releasecard
move.l a5,a1
bsr init_nic ; attempt to start controller
tst.l d0
beq.s .good
.releasecard:
lea dd_cardhandle(a5),a1
move.l dd_cardres(a5),a6
moveq #0,d0
jsr _LVOReleaseCard(a6) ; release foreign or bad card
bclr #DDB_OWNED,dd_flags(a5)
bra.s .done
.good:
btst #DDB_OFFLINE,dd_flags(a5) ; has device been put offline ?
bne.s .done
bset #DDB_ONLINE,dd_flags(a5) ; device is now online
move.l a5,a0
moveq #S2EVENT_ONLINE,D0
bsr DoEvent ; return ONLINE event
.done:
rts
;============================================================
; PCMCIA Card Removed interrupt
;============================================================
;
; Occurs whenever a PCMCIA card is unplugged
;
card_removed_code:
bug <"cnet: card removed",10>
move.l a1,a5
and.b #~(DDF_OWNED!DDF_CARDIN!DDF_ONLINE!DDF_NICUP),dd_flags(a5)
lea dd_cardhandle(a5),a1
move.l dd_cardres(a5),a6
moveq #0,d0
jsr _LVOReleaseCard(a6) ; release card
move.l a5,a0
moveq #S2EVENT_OFFLINE,D0
bsr DoEvent ; return OFFLINE event
rts
rxintname:
dc.b "cnet rx softint",0
txintname:
dc.b "cnet tx softint",0
cardname:
dc.b "card.resource",0
DeviceName:
dc.b "cnet.device",0
IDString:
dc.b "$VER: cnet.device "
dc.b (VERSION+"0"),".",(REVISION+"0")," "
dc.b __DATE
dc.b " by Bruce Abbott (bhabbott@inhb.co.nz)",10,0
even
; devicequery block
size_supplied:
dc.l S2DQ_SIZE ; bytes supplied (size of this block)
dc.l 0 ; this is type 0
dc.l 0 ; this document is level 0
dc.w ETHER_ADDR_SIZE*8 ; address size in bits
dc.l ETHERPKT_SIZE ; maximum packet data size
dc.l 10000000 ; line rate (10 Megabits/sec)
dc.l S2WIRETYPE_ETHERNET ; what the wire is
; default station address to use if the card won't give it to us.
default_address:
dc.b $00,$00,$12,$34,$56,$78 ; replace this with your card's address!
;--------------------------------------------------------
; Global data
;--------------------------------------------------------
execbase dc.l 0 ; local copy of execbase
tuple:
ds.b 48 ; PCMCIA tuple buffer
rx_header:
ds.b 20 ; received packet header
Endcode:
section buffers,bss
rxbuffer:
ds.b 1600 ; received packet buffer
txbuffer:
ds.b 1600 ; transmit packet buffer